package own.stu.bytebuffer.sim.agent;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

//@Data
//@Slf4j
public class Cached {

    static Cache<String, AtomicInteger> cache;
    static Level level = null;
    /*static {
        // 如果需要在线程中设置特定的种子
        long seed = System.nanoTime();
        ThreadLocalRandom random = ThreadLocalRandom.current();
        random.setSeed(seed);
    }*/
    static CacheConfig config = null;

    public static List<String> methodWords = new ArrayList();

    {
        methodWords.add("App");
        methodWords.add("Document");
        methodWords.add("UtilsController");
        methodWords.add("upload");
        methodWords.add("FlowForm");
        methodWords.add("message");
        methodWords.add("Login");
        methodWords.add("permission");
        methodWords.add("scheduletask");
        methodWords.add("base");
        methodWords.add("Tenant");
        methodWords.add("visualdata");
        methodWords.add("portal");
        methodWords.add("onlinedev");
        methodWords.add("generater");
        methodWords.add("integrate");
        methodWords.add("engine");
        methodWords.add("form");
        methodWords = wordCase(methodWords);
    }

    private static List<String> wordCase(List<String> methodWords){
        return methodWords.stream().map(v -> v.toLowerCase()).collect(Collectors.toList());
    }

    public static boolean filter(String key){
        for (String methodWord : methodWords) {
            if(key.indexOf(methodWord) >= 0){
                return true;
            }
        }
        return false;
    }

    public static void init() {
        cache = Caffeine.newBuilder()
                .maximumSize(2000)
                // 设置条目在写入后10分钟过期
                .expireAfterWrite(1, TimeUnit.HOURS)
                // 设置键使用弱引用
                .weakKeys()
                // 设置值使用软引用
                //.softValues()
                // 构建缓存
                .build();
        config = new CacheConfig();
        config.setLevel(2);
        level = Level.getByLevel(config.getLevel());
    }

    public static void setLevel(int levelV) {
        if (level != null) {
            if (level.level == levelV || levelV <= 0 || levelV > 4) {
                return;
            }
            int oldLevel = level.level;
            config.setLevel(levelV);
            level = Level.getByLevel(config.getLevel());
            // log.info("level change from {} to {}", oldLevel, levelV);
            // TODO del
            System.out.println("level change from  " + oldLevel + "to" + levelV);
        }
    }

    static {
        init();
    }

    /*public static void main(String[] args) throws InterruptedException {

        ExecutorService executorService = Executors.newFixedThreadPool(10);
        int threadNum = 10;
        CountDownLatch latch = new CountDownLatch(threadNum);
        // 初始化缓存
        for (int i = 0; i < threadNum; i++) {
            int finalI = i;
            executorService.submit(() -> {
                for (int j = 0; j < 100; j++)
                    intercept(v -> {
                        log.info("xxxxx - " + v);
                        return v;
                    }, finalI + "", finalI + "-" + j);

                latch.countDown();
            });
        }

        System.out.println(" ----- ");
        latch.await();
        System.out.println(" ========= ");
        ConcurrentMap<String, AtomicInteger> map = cache.asMap();
        for (Map.Entry<String, AtomicInteger> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " - " + entry.getValue());
        }
        executorService.shutdown();
    }*/

    static Object intercept(Function<Object, Object> consumer, String key, Object inParam) {
        int randNum = ThreadLocalRandom.current().nextInt(randomSeed);
        if (randNum < level.rate) {
            AtomicInteger value = cache.get(key.trim().intern(), v -> new AtomicInteger());
            if (value.get() <= level.rate && value.getAndIncrement() <= level.rate) {
                return consumer.apply(inParam);
            }
        }
        return inParam;
    }

    //@Data
    private static class CacheConfig {
        int level;
        int cacheExpire = 10; // sec

        public int getLevel() {
            return level;
        }

        public void setLevel(int level) {
            this.level = level;
        }

        public int getCacheExpire() {
            return cacheExpire;
        }

        public void setCacheExpire(int cacheExpire) {
            this.cacheExpire = cacheExpire;
        }
    }

    static int randomSeed = 100;

    enum Level {
        light(1, 2),
        normal(2, 10),
        heavy(3, 20),
        all(4, Integer.MAX_VALUE),
        ;
        int rate;
        int level;

        Level(int level, int rate) {
            this.level = level;
            this.rate = rate;
        }

        public int getRate() {
            return rate;
        }

        public static Level getByLevel(int level) {
            Level[] values = Level.values();
            for (Level value : values) {
                if (value.level == level) {
                    return value;
                }
            }
            return null;
        }
    }


}
